package AppleCakeMining;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import util.FileHandler;

public class Main {
	private static GlobalTransactionList tl;
	public static float MINFREQ = 0.003f;
	public static float MINCONF = 0.2f;
	public static int MINFREQPERCENT = 1;
	public static int MINCONFPERCENT = 10;
	
	public enum InterestingnessMeasure {CONFIDENCE, LIFT}
	public static InterestingnessMeasure measure = InterestingnessMeasure.CONFIDENCE;
	
	private static ArrayList<ItemSetList> itemSets;
	
	private static String SONGS = "kaggle_songs.txt";
	//private static String DATA ="kaggle_visible_evaluation_triplets.txt";
	//private static String DATA ="test.txt";
	private static String DATA = "data/cluster0.txt";
	private static String USERS ="kaggle_users.txt";
	
	//true if ids of users and songs are strings, false if integers
	private static boolean STRINGIDS = false; 
	
	
	
	
	public static void main(String[] args) {
		if(STRINGIDS) {
			readData();
			FileHandler.getInstance().deleteGlobalFile();
			System.out.println("Reading finished!");
			generateOneItemsets();
			
			boolean morePossible = generateItemsets();
			while(morePossible) {
				morePossible = generateItemsets();
			}
			System.out.println("ItemSets generated");
			//saveItemSets();
			generateRules();
			//saveRules();
			System.out.println("Finished itemset and rule generation!");
			
			predictExtensions(-1);
			System.out.println("Finnished!");
		}
		else {
			for(int i = 0; i < 100; ++i) {
				GlobalTransactionList.getInstance().clear();
				GlobalItemSetList.getInstance().clear();
				GlobalItemList.getInstance().clear();
				GlobalAssociationRuleList.getInstance().clear();
				readDataIntegers("data/cluster"+i+".txt");
				FileHandler.getInstance().deleteGlobalFile();
				System.out.println("Reading finished!");
				generateOneItemsets();
				
				boolean morePossible = generateItemsets();
				while(morePossible) {
					morePossible = generateItemsets();
				}
				System.out.println("ItemSets generated");
				//saveItemSets();
				generateRules();
				//saveRules();
				System.out.println("Finished itemset and rule generation!");
				
				predictExtensions(i);
				System.out.println("---------Finnished with cluster " + i);
			}
		}
		
	}

	//1-itemsets
	private static void generateOneItemsets() {
		int totalTransactions = GlobalTransactionList.getInstance().getTotalTransactions();
		int minSupport = (int) (totalTransactions * MINFREQ);
		itemSets = new ArrayList<ItemSetList>();
		
		
		ItemSetList oneItemsets = GlobalItemList.getInstance().calculateOneItemSets(minSupport, totalTransactions);
		itemSets.add(oneItemsets);
		System.out.println("1-itemsets generated");
		
	}
	
	//k-itemsets
	private static boolean generateItemsets() {
		int totalTransactions = GlobalTransactionList.getInstance().getTotalTransactions();
		int minSupport = (int) (totalTransactions * MINFREQ);
		
		ItemSetList nextSize = itemSets.get(itemSets.size()-1).generateNextSize(minSupport);
		itemSets.add(nextSize);
		System.out.println(itemSets.size() +"-itemsets generated");
		return nextSize.getItemSetNumber() > 0;
	}
	
	private static void clearUselessItemSets() {
		if(itemSets.size() >= 3) {
			itemSets.remove(0);
		}
	}
	
	private static void saveItemSets() {
		System.out.println("Saving itemsets");
		GlobalItemSetList gisl = GlobalItemSetList.getInstance();
		gisl.printAllFrequentItemSets();
		System.out.println("Itemsets saved");
		//GlobalAssociationRuleList.getInstance().printAllRules();
	}
	

	private static void saveRules() {
		System.out.println("Saving rules to files....");
		GlobalAssociationRuleList.getInstance().printAllRules();
	}

	private static void generateRules() {
		//generating association rules for all frequent itemsets
		System.out.println("Creating association rules...");
		GlobalItemSetList.getInstance().generateRules(MINCONF);
		System.out.println("Association rules created.");
	}
	
	private static void predictExtensions(int cluster) {
		System.out.println("Predicting the best songs for each user");
		FileHandler.getInstance().deleteFile("extension"+cluster+".txt");
		GlobalAssociationRuleList garl = GlobalAssociationRuleList.getInstance();
		int i = 0;
		//for each user, predicts 500 songs that he also listened to, using the association rules
		for(Transaction t:tl.getTransactions()) {
			ArrayList<Item> bestExtension = garl.generateBestExtension(t);
			//System.out.println(bestExtension.size());
			saveExtension(bestExtension, cluster, t.getId());
			System.out.println("User " + i++ + "'s songs predicted");
		}
	}

	private static void saveExtension(ArrayList<Item> bestExtension, int cluster, int userId) {
		String s = "";
		if(cluster >= 0) { //we are clustering
			s = userId + "-";
		}
		for(Item i:bestExtension) {
			s +=i.getId()+" ";
		}
		if(s.length() > 0) s = s.substring(0, s.length()-1);//last space removed
		s += "\n";
		
		FileHandler.getInstance().write(s, "extension"+cluster+".txt");
	}

	private static void readData() {
		tl = GlobalTransactionList.getInstance();
		FileReader fr;
		
		//first, we read the file that associates songs to ids
		Mappings mappings = Mappings.getInstance();
		try {
			fr = new FileReader(SONGS);
			BufferedReader in = new BufferedReader(fr);
			while (true) {
				try {
					String read = in.readLine();
					if (read == null || read.length() == 0)	break;
					String[] split = read.split(" ");
					//System.out.println(split[0] + " : " + split[1]);
					mappings.songMappings.put(split[0], Integer.valueOf(split[1]));
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		//then users to ids
		try {
			fr = new FileReader(USERS);
			BufferedReader in = new BufferedReader(fr);
			int i = 1;
			while (true) {
				try {
					String read = in.readLine();
					if (read == null || read.length() == 0)	break;
					mappings.userMappings.put(read, i);
					++i;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			fr = new FileReader(DATA);
			//fr = new FileReader("testdata2.txt");
			BufferedReader in = new BufferedReader(fr);
			String previousUser = "";
			Transaction t = null;
		
			while (true) {
				try {
					String read = in.readLine();
					if (read == null || read.length() == 0)	break;
					//System.out.println(read);
					String[] split = read.split("	");
					if(!split[0].equals(previousUser)) { //new user, new transaction
						if(t != null) tl.addTransaction(t); //we add the old, now complete, transaction
						//System.out.println("New user:" + split[0] + " Old one was: " + previousUser);
						t = new Transaction(mappings.userMappings.get(split[0])); 
						previousUser = split[0];
					}
					Integer id = mappings.songMappings.get(split[1]);
					GlobalItemList.getInstance().addItem(id, t);
					
					t.addItem(id); 
					
					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}	
		Mappings.getInstance().clear();
	}
	
	private static void readDataIntegers(String file) {
		FileReader fr;
		try {
			fr = new FileReader(file);
		
		//fr = new FileReader("testdata2.txt");
		BufferedReader in = new BufferedReader(fr);
		tl = GlobalTransactionList.getInstance();
		while (true) {
			try {
				
				String read = in.readLine();
				if (read == null || read.length() == 0)	break;
				//System.out.println(read);
				String[] firstSplit = read.split("-");
				System.out.println(firstSplit[0]);
				Integer id = Integer.valueOf(firstSplit[0].trim());
				String[] split = firstSplit[1].trim().split(" ");
				Transaction t = new Transaction(Integer.valueOf(id));
				for(String s:split) {
					t.addItem(Integer.valueOf(s));
					GlobalItemList.getInstance().addItem(Integer.valueOf(s), t);
				}
				tl.addTransaction(t); //we add the transaction
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
	}

}
